import ctypes

# ============ Win32/ctypes 定义 ============

user32 = ctypes.windll.user32
SendInput = user32.SendInput

# 一些常量
INPUT_MOUSE = 0
INPUT_KEYBOARD = 1
KEYEVENTF_KEYUP = 0x0002
MOUSEEVENTF_LEFTDOWN = 0x0002
MOUSEEVENTF_LEFTUP = 0x0004
MOUSEEVENTF_RIGHTDOWN = 0x0008
MOUSEEVENTF_RIGHTUP = 0x0010

VK_SHIFT = 0x10  # Shift 的虚拟键码

# 数字键虚拟键码 (1-9)
VK_1 = 0x31
VK_2 = 0x32
VK_3 = 0x33
VK_4 = 0x34
VK_5 = 0x35
VK_6 = 0x36
VK_7 = 0x37
VK_8 = 0x38
VK_9 = 0x39

# X键虚拟键码
VK_X = 0x58


# 结构体：MOUSEINPUT、KEYBDINPUT、HARDWAREINPUT、INPUT_UNION、INPUT
class MOUSEINPUT(ctypes.Structure):
    _fields_ = [("dx", ctypes.c_long), ("dy", ctypes.c_long), ("mouseData", ctypes.c_ulong),
        ("dwFlags", ctypes.c_ulong), ("time", ctypes.c_ulong), ("dwExtraInfo", ctypes.POINTER(ctypes.c_ulong))]


class KEYBDINPUT(ctypes.Structure):
    _fields_ = [("wVk", ctypes.c_ushort), ("wScan", ctypes.c_ushort), ("dwFlags", ctypes.c_ulong),
        ("time", ctypes.c_ulong), ("dwExtraInfo", ctypes.POINTER(ctypes.c_ulong))]


class HARDWAREINPUT(ctypes.Structure):
    _fields_ = [("uMsg", ctypes.c_ulong), ("wParamL", ctypes.c_short), ("wParamH", ctypes.c_ushort)]


class INPUT_UNION(ctypes.Union):
    _fields_ = [("mi", MOUSEINPUT), ("ki", KEYBDINPUT), ("hi", HARDWAREINPUT)]


class INPUT(ctypes.Structure):
    _fields_ = [("type", ctypes.c_ulong), ("union", INPUT_UNION)]


SendInput.argtypes = (ctypes.c_uint, ctypes.POINTER(INPUT), ctypes.c_int)
SendInput.restype = ctypes.c_uint

# 预先创建的鼠标INPUT结构, 以减少每次点击时的对象创建开销
# 左键
_LEFT_INPUTS = (INPUT * 2)()
_LEFT_INPUTS[0].type = INPUT_MOUSE
_LEFT_INPUTS[0].union.mi = MOUSEINPUT(0, 0, 0, MOUSEEVENTF_LEFTDOWN, 0, None)
_LEFT_INPUTS[1].type = INPUT_MOUSE
_LEFT_INPUTS[1].union.mi = MOUSEINPUT(0, 0, 0, MOUSEEVENTF_LEFTUP, 0, None)

# 右键
_RIGHT_INPUTS = (INPUT * 2)()
_RIGHT_INPUTS[0].type = INPUT_MOUSE
_RIGHT_INPUTS[0].union.mi = MOUSEINPUT(0, 0, 0, MOUSEEVENTF_RIGHTDOWN, 0, None)
_RIGHT_INPUTS[1].type = INPUT_MOUSE
_RIGHT_INPUTS[1].union.mi = MOUSEINPUT(0, 0, 0, MOUSEEVENTF_RIGHTUP, 0, None)

# 常用按键的预创建结构
# Shift按下
_SHIFT_DOWN = (INPUT * 1)()
_SHIFT_DOWN[0].type = INPUT_KEYBOARD
_SHIFT_DOWN[0].union.ki = KEYBDINPUT(wVk=VK_SHIFT, wScan=0, dwFlags=0, time=0, dwExtraInfo=None)

# Shift松开
_SHIFT_UP = (INPUT * 1)()
_SHIFT_UP[0].type = INPUT_KEYBOARD
_SHIFT_UP[0].union.ki = KEYBDINPUT(wVk=VK_SHIFT, wScan=0, dwFlags=KEYEVENTF_KEYUP, time=0, dwExtraInfo=None)

# 缓存常用键的INPUT结构
_KEY_CACHE = {}


def _get_key_input(vk_code, is_up=False):
    """获取按键INPUT结构，优先从缓存获取"""
    cache_key = (vk_code, is_up)
    if cache_key not in _KEY_CACHE:
        inputs = (INPUT * 1)()
        inputs[0].type = INPUT_KEYBOARD
        inputs[0].union.ki = KEYBDINPUT(
            wVk=vk_code, 
            wScan=0, 
            dwFlags=KEYEVENTF_KEYUP if is_up else 0,
            time=0, 
            dwExtraInfo=None
        )
        _KEY_CACHE[cache_key] = inputs
    return _KEY_CACHE[cache_key]


def press_key(vk_code: int):
    """模拟键盘按下某个虚拟键码"""
    # 使用Shift优化版本
    if vk_code == VK_SHIFT:
        SendInput(1, _SHIFT_DOWN, ctypes.sizeof(INPUT))
    else:
        # 其他键从缓存获取
        inputs = _get_key_input(vk_code, is_up=False)
        SendInput(1, inputs, ctypes.sizeof(INPUT))


def release_key(vk_code: int):
    """模拟键盘松开某个虚拟键码"""
    # 使用Shift优化版本
    if vk_code == VK_SHIFT:
        SendInput(1, _SHIFT_UP, ctypes.sizeof(INPUT))
    else:
        # 其他键从缓存获取
        inputs = _get_key_input(vk_code, is_up=True)
        SendInput(1, inputs, ctypes.sizeof(INPUT))


def is_shift_pressed():
    """检测当前是否按着 Shift 键。"""
    state = user32.GetAsyncKeyState(VK_SHIFT)
    return (state & 0x8000) != 0  # 最高位表示是否按下


def click_mouse(button='left'):
    """
    使用统一的 INPUT 结构体模拟鼠标点击。
    button 参数可选 'left' 或 'right'
    """
    # 使用预先创建的结构体而不是每次创建新的
    if button == 'left':
        SendInput(2, _LEFT_INPUTS, ctypes.sizeof(INPUT))
    else:  # right
        SendInput(2, _RIGHT_INPUTS, ctypes.sizeof(INPUT))


def switch_hotbar_slot(slot_number):
    """
    切换物品栏位置（1-9）
    slot_number: 1-9的整数
    """
    if not (1 <= slot_number <= 9):
        raise ValueError("物品栏位置必须在1-9之间")
    
    # 获取对应的虚拟键码
    vk_codes = {1: VK_1, 2: VK_2, 3: VK_3, 4: VK_4, 5: VK_5, 
                6: VK_6, 7: VK_7, 8: VK_8, 9: VK_9}
    vk_code = vk_codes[slot_number]
    
    # 模拟按下并松开数字键
    press_key(vk_code)
    release_key(vk_code)


def is_x_key_pressed():
    """检测当前是否按着 X 键"""
    state = user32.GetAsyncKeyState(VK_X)
    return (state & 0x8000) != 0


def set_window_transparency(master):
    """设置窗口透明度（仅适用于Windows）"""
    try:
        hwnd = ctypes.windll.user32.GetParent(master.winfo_id())

        class ACCENT_POLICY(ctypes.Structure):
            _fields_ = [("AccentState", ctypes.c_int), ("AccentFlags", ctypes.c_int),
                ("GradientColor", ctypes.c_int), ("AnimationId", ctypes.c_int), ]

        DWMWA_ACCENT_POLICY = 19
        accent = ACCENT_POLICY()
        accent.AccentState = 3
        accent.AccentFlags = 2
        accent.GradientColor = 0
        accent.AnimationId = 0
        accent_struct = ctypes.byref(accent)

        ctypes.windll.dwmapi.DwmSetWindowAttribute(hwnd, DWMWA_ACCENT_POLICY, accent_struct, ctypes.sizeof(accent))

        class MARGINS(ctypes.Structure):
            _fields_ = [("cxLeftWidth", ctypes.c_int), ("cxRightWidth", ctypes.c_int),
                ("cyTopHeight", ctypes.c_int), ("cyBottomHeight", ctypes.c_int), ]

        margins = MARGINS(-1, -1, -1, -1)
        ctypes.windll.dwmapi.DwmExtendFrameIntoClientArea(hwnd, ctypes.byref(margins))
    except Exception as e:
        print(f"设置窗口透明度失败: {e}") 